package com.ssy.lingxi.pay.serviceimpl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.order.OrderPaymentParameterEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.component.redis.service.IRedisStringUtils;
import com.ssy.lingxi.component.redis.utils.SerialNumberUtils;
import com.ssy.lingxi.member.merchant.api.constant.MemberPayPasswordCheckEnum;
import com.ssy.lingxi.member.merchant.api.feign.inner.MemberInnerControllerFeign;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.request.MemberFeignPayPswCheckVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.request.MemberFeignSubVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.request.MemberFeignVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.request.MemberRelationFeignVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.response.MemberFeignLogoVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.response.MemberFeignPayPswCheckResultVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.response.MemberFeignQueryVO;
import com.ssy.lingxi.order.api.model.vo.response.PayChannelParameterFeignDetailVO;
import com.ssy.lingxi.order.api.model.vo.response.PaymentParameterFeignDetailVO;
import com.ssy.lingxi.pay.api.common.CreditTradeConstant;
import com.ssy.lingxi.pay.api.common.ServiceTypeEnum;
import com.ssy.lingxi.pay.api.dto.request.MobilePayRequest;
import com.ssy.lingxi.pay.api.dto.request.assetAccount.BalancePayRequest;
import com.ssy.lingxi.pay.api.model.vo.request.*;
import com.ssy.lingxi.pay.api.model.vo.response.CreditFeignDetailVO;
import com.ssy.lingxi.pay.api.model.vo.response.CreditPayResponseVO;
import com.ssy.lingxi.pay.common.*;
import com.ssy.lingxi.pay.constant.Constants;
import com.ssy.lingxi.pay.entity.CreditApplyDO;
import com.ssy.lingxi.pay.entity.CreditBillDO;
import com.ssy.lingxi.pay.entity.CreditDO;
import com.ssy.lingxi.pay.entity.CreditTradeRecordDO;
import com.ssy.lingxi.pay.model.bo.PayProveBO;
import com.ssy.lingxi.pay.model.vo.request.*;
import com.ssy.lingxi.pay.model.vo.response.*;
import com.ssy.lingxi.pay.repository.CreditApplyRepository;
import com.ssy.lingxi.pay.repository.CreditBillRepository;
import com.ssy.lingxi.pay.repository.CreditRepository;
import com.ssy.lingxi.pay.repository.CreditTradeRecordRepository;
import com.ssy.lingxi.pay.service.ICreditApplyService;
import com.ssy.lingxi.pay.service.ICreditBillService;
import com.ssy.lingxi.pay.service.ICreditService;
import com.ssy.lingxi.pay.service.IFeignService;
import com.ssy.lingxi.pay.utils.CreditUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 会员授信接口实现
 * @author 伍将
 * @date 2020/8/13 15:55
 * @version 2.0.0
 */
@Service
public class CreditServiceImpl implements ICreditService {
    private static final Logger logger = LoggerFactory.getLogger(CreditServiceImpl.class);

    @Resource
    private CreditRepository creditRepository;

    @Resource
    private ICreditApplyService applyService;

    @Resource
    private CreditApplyRepository applyRepository;

    @Resource
    private ICreditBillService billService;

    @Resource
    private MemberInnerControllerFeign memberInnerControllerFeign;

    @Resource
    private CreditBillRepository billRepository;

    @Resource
    private CreditTradeRecordRepository tradeRecordRepository;

    @Resource
    private IRedisStringUtils redisStringUtils;

    @Resource
    private IFeignService feignService;

    /**
     * 初始化会员授信
     * @param initVO 接口参数
     * @return 初始化结果
     */
    @Transactional
    @Override
    public Wrapper<Void> init(CreditInitVO initVO) {
        logger.info("初始化授信申请记录initVO:{}", JSONUtil.toJsonStr(initVO));
        // step 1: 查询父级会员是否开启授信支付
        boolean isPass = feignService.isCreditPayment(initVO.getMemberId(), initVO.getRoleId());
        if (isPass) {
            // step 3: 开启授信支付，进行业务逻辑处理

            // step 3.1: 查询子会员列表数据
            MemberFeignSubVO memberFeignVO = new MemberFeignSubVO();
            memberFeignVO.setMemberId(initVO.getMemberId());
            memberFeignVO.setRoleId(initVO.getRoleId());
            Wrapper<List<MemberFeignQueryVO>> listWrapper = memberInnerControllerFeign.listLowerMembers(memberFeignVO);
            if(listWrapper == null){
                return Wrapper.fail(ResponseCode.FEIGN_SERVICE_ERROR);
            }else if(listWrapper.getCode() != ResponseCode.SUCCESS.getCode()){
                return Wrapper.fail(listWrapper);
            }
            List<MemberFeignQueryVO> memberList = listWrapper.getData();
            if (!CollectionUtils.isEmpty(memberList)) {
                // step 3.2: 查询未产生授信数据的子会员
                List<CreditDO> childList = creditRepository.findByParentMemberIdAndParentMemberRoleId(initVO.getMemberId(), initVO.getRoleId());
                // 定义全局的到期时间
                Long expireTime = CreditUtil.getExpireTime(DateUtil.date(), Constants.PAY_CREDIT_DEFAULT_BILL_DAY, Constants.PAY_CREDIT_DEFAULT_BILL_REPAY_PERIOD).getTime();
                // 根据会员id+角色id，匹配尚未新增授信的数据，并生成待新增的授信
                // 以子会员id+子会员角色id为唯一键去重，得到需要新增的数据列表
                List<CreditDO> addList = memberList.stream()
                        .filter(member -> childList.stream().noneMatch(child -> child.getMemberId().equals(member.getMemberId()) && child.getMemberRoleId().equals(member.getRoleId())))
                        .map(r -> {
                            CreditDO addDO = new CreditDO();
                            addDO.setMemberId(r.getMemberId());
                            addDO.setMemberRoleId(r.getRoleId());
                            addDO.setParentMemberId(initVO.getMemberId());
                            addDO.setParentMemberRoleId(initVO.getRoleId());
                            addDO.setQuota(0D);
                            addDO.setUseQuota(0D);
                            addDO.setBillDay(Constants.PAY_CREDIT_DEFAULT_BILL_DAY);
                            addDO.setRepayPeriod(Constants.PAY_CREDIT_DEFAULT_BILL_REPAY_PERIOD);
                            addDO.setStatus(CreditStatusEnum.UN_APPLY.getCode());
                            addDO.setRePayStatus(CreditRepayStatusEnum.PAY_OFF.getCode());
                            addDO.setIsHasApply(EnableDisableStatus.DISABLE.getCode());
                            addDO.setCreateTime(System.currentTimeMillis());
                            addDO.setUpdateTime(0L);
                            addDO.setExpireTime(expireTime);
                            addDO.setLastRepayTime(0L);
                            addDO.setIsUsable(CommonBooleanEnum.NO.getCode());
                            return addDO;
                        }).collect(Collectors.toList());
                // step 3.3: 为未产生授信数据的子会员新增授信信息
                if (addList.size() > 0) {
                    creditRepository.saveAll(addList);
                }
            }
        }

        return Wrapper.success();
    }

    /**
     * 查询会员授信
     *
     * @param feignVO 上下级会员Id
     * @return 查询结果，如无授信，返回Null
     */
    @Override
    public Wrapper<CreditFeignDetailVO> findCredit(CreditFeignVO feignVO) {
        // 验证授信是否存在
        CreditDO creditDO = this.creditRepository.findFirstByMemberIdAndMemberRoleIdAndParentMemberIdAndParentMemberRoleId(feignVO.getMemberId(), feignVO.getRoleId(), feignVO.getParentMemberId(), feignVO.getParentMemberRoleId());
        if (creditDO == null) {
            return Wrapper.success(null);
        }

        CreditFeignDetailVO result = new CreditFeignDetailVO();

        // 赋值授信信息
        result.setQuota(creditDO.getQuota());
        result.setUseQuota(creditDO.getUseQuota());
        result.setCanUseQuota(creditDO.getQuota() - creditDO.getUseQuota());
        result.setIsUsable(creditDO.getIsUsable());
        return Wrapper.success(result);
    }

    /**
     * 新增授信
     * @param creditAddVO 接口参数
     * @return 新增结果
     */
    @Override
    public Wrapper<Void> add(CreditAddVO creditAddVO) {
        logger.info("添加授信申请记录creditAddVO:{}", JSONUtil.toJsonStr(creditAddVO));
        // step 1: 查询父级会员是否开启授信支付
        boolean isPass = feignService.isCreditPayment(creditAddVO.getParentMemberId(), creditAddVO.getParentMemberRoleId());
        if (!isPass) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_LINE_PAYMENT_NOT_OPEN);
        } else {
            // step 2: 验证是否存在相同数据
            CreditDO oldCreditDO = this.creditRepository.findFirstByMemberIdAndMemberRoleIdAndParentMemberIdAndParentMemberRoleId(
                    creditAddVO.getMemberId(), creditAddVO.getRoleId(), creditAddVO.getParentMemberId(), creditAddVO.getParentMemberRoleId());
            if (oldCreditDO != null) {
                return Wrapper.fail(ResponseCode.PAY_CREDIT_EXIST);
            }

            // step 5: 新增授信
            CreditDO creditDO = new CreditDO();
            creditDO.setMemberId(creditAddVO.getMemberId());
            creditDO.setMemberRoleId(creditAddVO.getRoleId());
            creditDO.setParentMemberId(creditAddVO.getParentMemberId());
            creditDO.setParentMemberRoleId(creditAddVO.getParentMemberRoleId());
            creditDO.setQuota(0D);
            creditDO.setUseQuota(0D);
            creditDO.setBillDay(Constants.PAY_CREDIT_DEFAULT_BILL_DAY);
            creditDO.setRepayPeriod(Constants.PAY_CREDIT_DEFAULT_BILL_REPAY_PERIOD);
            creditDO.setStatus(CreditStatusEnum.UN_APPLY.getCode());
            creditDO.setRePayStatus(CreditRepayStatusEnum.PAY_OFF.getCode());
            creditDO.setIsHasApply(EnableDisableStatus.DISABLE.getCode());
            creditDO.setCreateTime(System.currentTimeMillis());
            creditDO.setUpdateTime(0L);
            Long expireTime = CreditUtil.getExpireTime(DateUtil.date(), Constants.PAY_CREDIT_DEFAULT_BILL_DAY, Constants.PAY_CREDIT_DEFAULT_BILL_REPAY_PERIOD).getTime();
            creditDO.setExpireTime(expireTime);
            creditDO.setLastRepayTime(0L);
            creditDO.setIsUsable(CommonBooleanEnum.NO.getCode());
            this.creditRepository.saveAndFlush(creditDO);
        }

        return Wrapper.success();
    }

    /**
     * 分页获取会员授信
     * @param user 登录用户
     * @param pageVO 分页查询授信VO
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<CreditQueryVO>> pageCredit(UserLoginCacheDTO user, PageQueryCreditVO pageVO) {

        // 查询会员信息
        MemberFeignVO memberFeignVO = new MemberFeignVO();
        memberFeignVO.setMemberId(user.getMemberId());
        memberFeignVO.setRoleId(user.getMemberRoleId());
        Wrapper<List<MemberFeignQueryVO>> listWrapper = memberInnerControllerFeign.listUpperMembers(memberFeignVO);
        if(listWrapper == null){
            return Wrapper.fail(ResponseCode.FEIGN_SERVICE_ERROR);
        }else if(listWrapper.getCode() != ResponseCode.SUCCESS.getCode()){
            return Wrapper.fail(listWrapper);
        }

        // step 1: 组装查询条件
        Specification<CreditDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), user.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("memberRoleId").as(Long.class), user.getMemberRoleId()));
            if (!pageVO.getStatus().equals(CreditStatusEnum.ALL.getCode())) {
                list.add(criteriaBuilder.equal(root.get("status").as(int.class), pageVO.getStatus()));
            }
            if (!pageVO.getRePayStatus().equals(CreditRepayStatusEnum.ALL.getCode())) {
                list.add(criteriaBuilder.equal(root.get("rePayStatus").as(int.class), pageVO.getRePayStatus()));
            }
            // 筛选上级会员名称
            if (StringUtils.hasLength(pageVO.getParentMemberName())) {
                List<Long> idList = listWrapper.getData().stream()
                        .filter(r -> r.getMemberName().contains(pageVO.getParentMemberName()))
                        .map(MemberFeignQueryVO::getMemberId).collect(Collectors.toList());
                if(!CollectionUtils.isEmpty(idList)) {
                    list.add(root.get("parentMemberId").in(idList));
                }else{
                    list.add(criteriaBuilder.equal(root.get("parentMemberId").as(Long.class),-1L));
                }
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // step 2: 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("updateTime").descending());

        // step 3: 分页查询数据
        Page<CreditDO> result = this.creditRepository.findAll(spec, page);

        // step 4: 组装返回数据
        List<CreditQueryVO> resultList = result.getContent().stream().map(r -> {
            CreditQueryVO queryVO = new CreditQueryVO();
            queryVO.setId(r.getId());

            MemberFeignQueryVO memberFeignQueryVO = listWrapper.getData().stream().filter(item -> item.getMemberId().equals(r.getParentMemberId())
                    && item.getRoleId().equals(r.getParentMemberRoleId())).findFirst().orElse(null);
            if (memberFeignQueryVO != null) {
                queryVO.setParentMemberName(memberFeignQueryVO.getMemberName());
                queryVO.setMemberTypeName(memberFeignQueryVO.getMemberTypeName());
                queryVO.setMemberRoleName(memberFeignQueryVO.getRoleName());
                queryVO.setMemberLevelName(memberFeignQueryVO.getLevelTag());
            }
            queryVO.setQuota(r.getQuota());
            queryVO.setUseQuota(r.getUseQuota());
            queryVO.setCanUseQuota(Double.valueOf(String.format("%.2f", r.getQuota() - r.getUseQuota())));
            queryVO.setStatus(r.getStatus());
            queryVO.setStatusName(CreditStatusEnum.getItem(r.getStatus()).getMessage());
            queryVO.setRepayStatus(r.getRePayStatus());
            queryVO.setIsHasApply(r.getIsHasApply());

            CreditRepayStatusEnum repayStatusEnum = CreditRepayStatusEnum.getItem(r.getRePayStatus());
            if (CreditRepayStatusEnum.OVERDUE.getCode().equals(r.getRePayStatus())) {
                // 如果支付状态为逾期，则计算逾期天数
                Long overdueDay = DateUtil.between(DateUtil.date(r.getExpireTime()), DateUtil.date(), DateUnit.DAY, false);
                queryVO.setOverdueDay(overdueDay);
                String repayStatusName = repayStatusEnum.getRemark() + overdueDay + "天";
                queryVO.setRepayStatusName(repayStatusName);

            } else {
                queryVO.setOverdueDay(0L);
                queryVO.setRepayStatusName(repayStatusEnum.getRemark());
            }
            queryVO.setIsCanApply(CommonBooleanEnum.YES.getCode());
            CreditApplyDO applyDo = applyRepository.findByIsCurrentAndCreditIdAndIsDelete(CommonBooleanEnum.YES.getCode(), r.getId(), CommonBooleanEnum.NO.getCode());
            if (applyDo != null) {
                PaymentParameterFeignDetailVO payParameters = feignService.getCreditPayment(r.getParentMemberId(), r.getParentMemberRoleId());
                if (payParameters != null && !CollectionUtils.isEmpty(payParameters.getParameters())) {
                    // 获取允许申请的间隔天数
                    PayChannelParameterFeignDetailVO detailVO  = payParameters.getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.CREDIT_DAYS) && StringUtils.hasLength(p.getValue())).findFirst().orElse(null);
                    long intervalDay = detailVO == null ? 0L : Long.parseLong(detailVO.getValue());
                    long betweenDay = DateUtil.between(
                            DateUtil.date(applyDo.getApplyTime()),
                            DateUtil.date(System.currentTimeMillis()),
                            DateUnit.DAY);
                    // 间隔时间小于等配置时间则不允许再次申请
                    if (betweenDay < intervalDay) {
                        queryVO.setIsCanApply(CommonBooleanEnum.NO.getCode());
                    }
                } else {
                    queryVO.setIsCanApply(CommonBooleanEnum.NO.getCode());
                }
            }

            return queryVO;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    /**
     * App端分页查询会员授信
     * @param user 登录用户
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<CreditQueryAppVO>> pageCreditByApp(UserLoginCacheDTO user, PageQueryCreditVO pageVO) {

        // 查询会员信息
        MemberFeignVO memberFeignVO = new MemberFeignVO();
        memberFeignVO.setMemberId(user.getMemberId());
        memberFeignVO.setRoleId(user.getMemberRoleId());
        Wrapper<List<MemberFeignQueryVO>> listWrapper = memberInnerControllerFeign.listUpperMembers(memberFeignVO);
        if(listWrapper == null){
            return Wrapper.fail(ResponseCode.FEIGN_SERVICE_ERROR);
        }else if(listWrapper.getCode() != ResponseCode.SUCCESS.getCode()){
            return Wrapper.fail(listWrapper);
        }
        // step 1: 组装查询条件
        Specification<CreditDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), user.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("memberRoleId").as(Long.class), user.getMemberRoleId()));
            if (!pageVO.getStatus().equals(CreditStatusEnum.ALL.getCode())) {
                list.add(criteriaBuilder.equal(root.get("status").as(int.class), pageVO.getStatus()));
            }
            if (!pageVO.getRePayStatus().equals(CreditRepayStatusEnum.ALL.getCode())) {
                list.add(criteriaBuilder.equal(root.get("rePayStatus").as(int.class), pageVO.getRePayStatus()));
            }
            // 筛选上级会员名称
            if (StringUtils.hasLength(pageVO.getParentMemberName())) {
                List<Long> idList = listWrapper.getData().stream()
                        .filter(r -> r.getMemberName().contains(pageVO.getParentMemberName()))
                        .map(MemberFeignQueryVO::getMemberId).collect(Collectors.toList());
                list.add(criteriaBuilder.in(root.get("parentMemberId")).value(idList));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // step 2: 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("updateTime").descending());

        // step 3: 分页查询数据
        Page<CreditDO> result = this.creditRepository.findAll(spec, page);

        // 查询log
        List<Long> memberIds = result.getContent().stream().map(CreditDO::getParentMemberId).collect(Collectors.toList());
        Wrapper<List<MemberFeignLogoVO>> logListWrapper = memberInnerControllerFeign.getMemberLogos(memberIds);
        if(logListWrapper == null){
            return Wrapper.fail(ResponseCode.FEIGN_SERVICE_ERROR);
        }else if(logListWrapper.getCode() != ResponseCode.SUCCESS.getCode()){
            return Wrapper.fail(logListWrapper);
        }
        // step 4: 组装返回数据
        List<CreditQueryAppVO> resultList = result.getContent().stream().map(r -> {
            CreditQueryAppVO queryVO = new CreditQueryAppVO();
            queryVO.setId(r.getId());
            MemberFeignQueryVO memberFeignQueryVO = listWrapper.getData().stream().filter(item -> item.getMemberId().equals(r.getParentMemberId())
                    && item.getRoleId().equals(r.getParentMemberRoleId())).findFirst().orElse(null);
            if (memberFeignQueryVO != null) {
                queryVO.setParentMemberName(memberFeignQueryVO.getMemberName());
                queryVO.setMemberTypeName(memberFeignQueryVO.getMemberTypeName());
                queryVO.setMemberRoleName(memberFeignQueryVO.getRoleName());
                queryVO.setMemberLevelName(memberFeignQueryVO.getLevelTag());
                queryVO.setLogo(memberFeignQueryVO.getLogo());
            }
            queryVO.setQuota(r.getQuota());
            queryVO.setUseQuota(r.getUseQuota());
            queryVO.setCanUseQuota(Double.valueOf(String.format("%.2f", r.getQuota() - r.getUseQuota())));
            queryVO.setStatus(r.getStatus());
            queryVO.setStatusName(CreditStatusEnum.getItem(r.getStatus()).getMessage());
            queryVO.setRepayStatus(r.getRePayStatus());
            queryVO.setIsHasApply(r.getIsHasApply());
            CreditRepayStatusEnum repayStatusEnum = CreditRepayStatusEnum.getItem(r.getRePayStatus());
            if (CreditRepayStatusEnum.OVERDUE.getCode().equals(r.getRePayStatus())) {
                // 如果支付状态为逾期，则计算逾期天数
                Long overdueDay = DateUtil.between(DateUtil.date(r.getExpireTime()), DateUtil.date(), DateUnit.DAY, false);
                queryVO.setOverdueDay(overdueDay);
                String repayStatusName = repayStatusEnum.getRemark() + overdueDay + "天";
                queryVO.setRepayStatusName(repayStatusName);

            } else {
                queryVO.setOverdueDay(0L);
                queryVO.setRepayStatusName(repayStatusEnum.getRemark());
            }
            queryVO.setIsCanApply(CommonBooleanEnum.YES.getCode());
            CreditApplyDO applyDo = applyRepository.findByIsCurrentAndCreditIdAndIsDelete(CommonBooleanEnum.YES.getCode(), r.getId(), CommonBooleanEnum.NO.getCode());
            if (applyDo != null) {
                PaymentParameterFeignDetailVO payParameters = feignService.getCreditPayment(r.getParentMemberId(), r.getParentMemberRoleId());
                if (payParameters != null) {
                    // 获取允许申请的间隔天数
                    PayChannelParameterFeignDetailVO detailVO = payParameters.getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.CREDIT_DAYS) && StringUtils.hasLength(p.getValue())).findFirst().orElse(null);
                    long intervalDay = detailVO == null ? 0L : Long.parseLong(detailVO.getValue());
                    long betweenDay = DateUtil.between(
                            DateUtil.date(applyDo.getApplyTime()),
                            DateUtil.date(System.currentTimeMillis()),
                            DateUnit.DAY);
                    // 间隔时间小于等配置时间则不允许再次申请
                    if (betweenDay < intervalDay) {
                        queryVO.setIsCanApply(CommonBooleanEnum.NO.getCode());
                    }
                } else {
                    queryVO.setIsCanApply(CommonBooleanEnum.NO.getCode());
                }
            }

            logListWrapper.getData().stream().filter(item -> item.getMemberId().equals(r.getParentMemberId())).findFirst().ifPresent(memberLogQueryVO -> queryVO.setParentMemberLog(memberLogQueryVO.getLogo()));

            return queryVO;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    /**
     * 分页获取子会员授信
     * @param user 登录用户
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<ChildCreditQueryVO>> pageChildCredit(UserLoginCacheDTO user, PageQueryChildCreditVO pageVO) {

        // 查询会员信息
        MemberFeignSubVO memberFeignVO = new MemberFeignSubVO();
        memberFeignVO.setMemberId(user.getMemberId());
        memberFeignVO.setRoleId(user.getMemberRoleId());
        memberFeignVO.setSubMemberName(pageVO.getMemberName());
        memberFeignVO.setLevel(pageVO.getLevel());
        memberFeignVO.setMemberTypeId(pageVO.getMemberTypeId());
        memberFeignVO.setSubRoleId(pageVO.getSubRoleId());
        Wrapper<List<MemberFeignQueryVO>> listWrapper = memberInnerControllerFeign.listLowerMembers(memberFeignVO);
        if(listWrapper == null){
            return Wrapper.fail(ResponseCode.FEIGN_SERVICE_ERROR);
        }else if(listWrapper.getCode() != ResponseCode.SUCCESS.getCode()){
            return Wrapper.fail(listWrapper);
        }
        List<Long> idList = listWrapper.getData().stream().map(MemberFeignQueryVO::getMemberId).collect(Collectors.toList());

        // step 1: 组装查询条件
        Specification<CreditDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("parentMemberId").as(Long.class), user.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("parentMemberRoleId").as(Long.class), user.getMemberRoleId()));
            if (!pageVO.getStatus().equals(CreditStatusEnum.ALL.getCode())) {
                list.add(criteriaBuilder.equal(root.get("status").as(int.class), pageVO.getStatus()));
            }
            if (!pageVO.getRePayStatus().equals(CreditRepayStatusEnum.ALL.getCode())) {
                list.add(criteriaBuilder.equal(root.get("rePayStatus").as(int.class), pageVO.getRePayStatus()));
            }
            // 增加会员筛选条件
            if (StringUtils.hasLength(pageVO.getMemberName())
                    || null != pageVO.getMemberTypeId()
                    || null != pageVO.getSubRoleId()
                    || null != pageVO.getLevel()) {
                list.add(criteriaBuilder.in(root.get("memberId")).value(idList));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // step 2: 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("updateTime").descending());

        // step 3: 分页查询数据
        Page<CreditDO> result = this.creditRepository.findAll(spec, page);

        // step 4: 组装返回数据
        List<ChildCreditQueryVO> resultList = result.getContent().stream().map(r -> {
            ChildCreditQueryVO queryVO = new ChildCreditQueryVO();
            queryVO.setId(r.getId());
            queryVO.setMemberId(r.getMemberId());
            MemberFeignQueryVO memberFeignQueryVO = listWrapper.getData().stream()
                    .filter(item -> item.getMemberId().equals(r.getMemberId())
                            && item.getRoleId().equals(r.getMemberRoleId())).findFirst().orElse(null);
            if (memberFeignQueryVO != null) {
                queryVO.setMemberName(memberFeignQueryVO.getMemberName());
                queryVO.setMemberTypeName(memberFeignQueryVO.getMemberTypeName());
                queryVO.setMemberRoleName(memberFeignQueryVO.getRoleName());
                queryVO.setMemberLevelName(memberFeignQueryVO.getLevelTag());
            }
            queryVO.setQuota(r.getQuota());
            queryVO.setUseQuota(r.getUseQuota());
            queryVO.setCanUseQuota(r.getQuota() - r.getUseQuota());
            queryVO.setStatus(r.getStatus());
            queryVO.setStatusName(CreditStatusEnum.getItem(r.getStatus()).getMessage());
            queryVO.setRepayStatus(r.getRePayStatus());
            queryVO.setIsHasApply(r.getIsHasApply());

            CreditRepayStatusEnum repayStatusEnum = CreditRepayStatusEnum.getItem(r.getRePayStatus());
            if (CreditRepayStatusEnum.OVERDUE.getCode().equals(r.getRePayStatus())) {
                // 如果支付状态为逾期，则计算逾期天数
                Long overdueDay = DateUtil.between(DateUtil.date(r.getExpireTime()), DateUtil.date(), DateUnit.DAY, false);
                queryVO.setOverdueDay(overdueDay);
                String repayStatusName = repayStatusEnum.getRemark() + overdueDay + "天";
                queryVO.setRepayStatusName(repayStatusName);
            } else {
                queryVO.setRepayStatusName(repayStatusEnum.getRemark());
            }

            CreditApplyDO applyDo = applyRepository.findByIsCurrentAndCreditIdAndIsDelete(CommonBooleanEnum.YES.getCode(), r.getId(), CommonBooleanEnum.NO.getCode());
            if (applyDo != null) {
                PaymentParameterFeignDetailVO payParameters = feignService.getCreditPayment(r.getParentMemberId(), r.getParentMemberRoleId());
                if (payParameters != null) {
                    // 获取允许申请的间隔天数
                    PayChannelParameterFeignDetailVO detailVO = payParameters.getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.CREDIT_DAYS) && StringUtils.hasLength(p.getValue())).findFirst().orElse(null);
                    long intervalDay = detailVO == null ? 0L : Long.parseLong(detailVO.getValue());
                    long betweenDay = DateUtil.between(
                            DateUtil.date(applyDo.getApplyTime()),
                            DateUtil.date(System.currentTimeMillis()),
                            DateUnit.DAY);
                    // 间隔时间小于等配置时间则不允许再次申请
                    if (betweenDay < intervalDay) {
                        queryVO.setIsCanApply(CommonBooleanEnum.NO.getCode());
                    } else {
                        queryVO.setIsCanApply(CommonBooleanEnum.YES.getCode());
                    }
                } else {
                    queryVO.setIsCanApply(CommonBooleanEnum.NO.getCode());
                }
            } else {
                queryVO.setIsCanApply(CommonBooleanEnum.NO.getCode());
            }

            return queryVO;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    /**
     * 更新会员授信状态
     * @param user 登录用户
     * @param memberCreditUpdateVO 接口参数
     * @return 记录Id
     */
    @Override
    public Wrapper<Long> updateCreditStatus(UserLoginCacheDTO user, CreditUpdateVO memberCreditUpdateVO) {

        // step 1: 验证修改的状态符合要求
        if (!CreditStatusEnum.THAW.getCode().equals(memberCreditUpdateVO.getStatus()) && !CreditStatusEnum.FROZEN.getCode().equals(memberCreditUpdateVO.getStatus())) {
            throw new BusinessException(ResponseCode.PAY_CREDIT_STATUS_PARAM_ERROR);
        }

        // step 2: 验证授信是否存在
        CreditDO creditDO = this.creditRepository.findById(memberCreditUpdateVO.getId()).orElse(null);
        if (creditDO == null) {
            throw new BusinessException(ResponseCode.PAY_CREDIT_NOT_EXIST);
        }

        // step 2.1: 修改状态为正常时，原数据状态必须为冻结
        if (CreditStatusEnum.THAW.getCode().equals(memberCreditUpdateVO.getStatus())) {
            if (!creditDO.getStatus().equals(CreditStatusEnum.FROZEN.getCode())) {
                throw new BusinessException(ResponseCode.PAY_CREDIT_STATUS_NOT_FROZEN);
            }
            creditDO.setIsUsable(CommonBooleanEnum.YES.getCode());
        }
        // step 2.2: 修改状态为冻结时，原数据状态必须为正常
        else {
            if (!creditDO.getStatus().equals(CreditStatusEnum.THAW.getCode())) {
                throw new BusinessException(ResponseCode.PAY_CREDIT_STATUS_NOT_THAW);
            }
            creditDO.setIsUsable(CommonBooleanEnum.NO.getCode());
        }
        creditDO.setStatus(memberCreditUpdateVO.getStatus());
        creditDO.setUpdateTime(System.currentTimeMillis());

        this.creditRepository.saveAndFlush(creditDO);

        return Wrapper.success(creditDO.getId());
    }

    /**
     * 获取授信详情
     * @param user 登录用户
     * @param id 记录Id
     * @param isUpperSle 是否上级查询
     * @return 查询结果
     */
    @Override
    public Wrapper<CreditDetailVO> getDetail(UserLoginCacheDTO user, Long id, Boolean isUpperSle) {

        // 验证授信是否存在
        CreditDO creditDO = this.creditRepository.findById(id).orElse(null);
        if (creditDO == null) {
            throw new BusinessException(ResponseCode.PAY_CREDIT_NOT_EXIST);
        }

        CreditDetailVO result = new CreditDetailVO();

        // 赋值授信信息
        result.setId(creditDO.getId());
        result.setQuota(creditDO.getQuota());
        result.setUseQuota(creditDO.getUseQuota());

        BigDecimal quota = new BigDecimal(Double.toString(creditDO.getQuota()));
        BigDecimal useQuota = new BigDecimal(Double.toString(creditDO.getUseQuota()));
        result.setCanUseQuota(quota.subtract(useQuota).doubleValue());
        result.setBillDay(creditDO.getBillDay());
        result.setRepayPeriod(creditDO.getRepayPeriod());
        result.setLastRepayTime(null != creditDO.getLastRepayTime() && creditDO.getLastRepayTime() > 0 ? DateUtil.format(DateUtil.date(creditDO.getLastRepayTime()), "yyyy-MM-dd") : "-");

        // 查询会员信息
        CreditMemberVO member = new CreditMemberVO();
        MemberRelationFeignVO memberRelationFeignVO = new MemberRelationFeignVO();
        memberRelationFeignVO.setMemberId(creditDO.getMemberId());
        memberRelationFeignVO.setRoleId(creditDO.getMemberRoleId());
        memberRelationFeignVO.setUpperMemberId(creditDO.getParentMemberId());
        memberRelationFeignVO.setUpperRoleId(creditDO.getParentMemberRoleId());
        Wrapper<MemberFeignQueryVO> memberFeignQueryVOWrapper = memberInnerControllerFeign.getMemberInfo(memberRelationFeignVO);
        if(memberFeignQueryVOWrapper == null){
            return Wrapper.fail(ResponseCode.FEIGN_SERVICE_ERROR);
        }else if(memberFeignQueryVOWrapper.getCode() != ResponseCode.SUCCESS.getCode()){
            return Wrapper.fail(memberFeignQueryVOWrapper);
        }
        // 赋值授信会员信息
        if (memberFeignQueryVOWrapper.getData() != null) {
            member.setMemberId(memberFeignQueryVOWrapper.getData().getMemberId());
            member.setParentMemberName(memberFeignQueryVOWrapper.getData().getMemberName());
            member.setMemberName(memberFeignQueryVOWrapper.getData().getSubMemberName());
            member.setMemberTypeName(memberFeignQueryVOWrapper.getData().getMemberTypeName());
            member.setRoleName(memberFeignQueryVOWrapper.getData().getRoleName());
            member.setRoleId(memberFeignQueryVOWrapper.getData().getRoleId());
            member.setLevelTag(memberFeignQueryVOWrapper.getData().getLevelTag());
            member.setLogo(memberFeignQueryVOWrapper.getData().getLogo());
        }
        member.setRepayStatus(creditDO.getRePayStatus());
        // 只要非冻结状态，其他状态返回正常
        if (CreditStatusEnum.FROZEN.getCode().equals(creditDO.getStatus())) {
            member.setStatus(creditDO.getStatus());
        } else {
            member.setStatus(CreditStatusEnum.THAW.getCode());
        }
        result.setMember(member);

        // 赋值授信账单下拉框信息
        Wrapper<List<CreditBillSelectVO>> billSelectWrapper = billService.getSelect(creditDO.getId());
        if (billSelectWrapper.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(billSelectWrapper);
        }
        if (billSelectWrapper.getData() != null && billSelectWrapper.getData().size() > 0) {
            result.setBillSelectList(billSelectWrapper.getData());
            // 赋值授信账单信息
            Wrapper<CreditBillDetailVO> billDetailWrapper = billService.getDetail(billSelectWrapper.getData().get(0).getId());
            if (billDetailWrapper.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(billDetailWrapper);
            }
            result.setBill(billDetailWrapper.getData());
        }

        // 赋值授信历史申请
        Wrapper<List<CreditHistoryApplyVO>> applyListWrapper = applyService.getHistoryList(id, isUpperSle);
        if(applyListWrapper.getCode() != ResponseCode.SUCCESS.getCode()){
            return Wrapper.fail(applyListWrapper);
        }
        result.setHistoryApplyList(applyListWrapper.getData());

        return Wrapper.success(result);
    }

    /**
     * 授信支付
     * @param payVO 接口参数
     * @return 支付结果
     */
    @Transactional
    @Override
    public Wrapper<CreditPayResponseVO> pay(CreditPayVO payVO) {
        if (!StringUtils.hasLength(payVO.getOrderCode())) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_PAY_ORDER_CODE_EMPTY);
        }

        CreditDO creditDO = creditRepository.findFirstByMemberIdAndMemberRoleIdAndParentMemberIdAndParentMemberRoleId(payVO.getMemberId(), payVO.getRoleId(), payVO.getParentMemberId(), payVO.getParentMemberRoleId());
        if (creditDO == null) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_NOT_EXIST);
        }
        // 会员本身未开启授信支付
        if (!creditDO.getIsUsable().equals(CommonBooleanEnum.YES.getCode())) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_PAYMENT_NOT_OPEN);
        }

        // 上级未开启授信支付
        boolean isPass = feignService.isCreditPayment(creditDO.getParentMemberId(), creditDO.getParentMemberRoleId());
        if (!isPass) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_LINE_PAYMENT_NOT_OPEN);
        }

        // 可用金额不足
        if ((creditDO.getQuota() - creditDO.getUseQuota()) < payVO.getPayMoney()) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_NOT_ENOUGH_BALANCE);
        }

        // 校验支付密码
        MemberFeignPayPswCheckVO checkVO = new MemberFeignPayPswCheckVO();
        checkVO.setMemberId(payVO.getMemberId());
        checkVO.setPayPassword(payVO.getPayPassword());
        Wrapper<MemberFeignPayPswCheckResultVO> checkResultVOWrapper = memberInnerControllerFeign.checkMemberPayPassword(checkVO);
        if(checkResultVOWrapper.getCode() != ResponseCode.SUCCESS.getCode()){
            return Wrapper.fail(checkResultVOWrapper);
        }

        if (!checkResultVOWrapper.getData().getCheckResult().equals(MemberPayPasswordCheckEnum.CORRECT.getCode())) {
            if (checkResultVOWrapper.getData().getCheckResult().equals(MemberPayPasswordCheckEnum.NOT_SET.getCode())) {
                // 支付密码未设置
                return Wrapper.fail(ResponseCode.PAY_CREDIT_PASSWORD_NOT_SET);
            } else if (checkResultVOWrapper.getData().getCheckResult().equals(MemberPayPasswordCheckEnum.INCORRECT.getCode())) {
                // 支付密码错误
                return Wrapper.fail(ResponseCode.PAY_CREDIT_PASSWORD_INCORRECT);
            } else {
                // 支付状态未知时，返回服务内部错误
                return Wrapper.fail(ResponseCode.BUSINESS_ERROR);
            }
        }

        // 修改当前账单
        int nowDay = DateUtil.date().dayOfMonth();
        long billBelongTime;
        // 当前天大于等于账单日，则账单所属时间为当月
        if (nowDay >= creditDO.getBillDay()) {
            billBelongTime = DateUtil.beginOfMonth(DateUtil.date()).getTime();
        } else {
            // 否则账单所属时间为前一月
            billBelongTime = DateUtil.offsetMonth(DateUtil.beginOfMonth(DateUtil.date()), -1).getTime();
        }

        CreditBillDO billDO = billRepository.findByBillBelongTimeAndCreditId(billBelongTime, creditDO.getId());
        if (billDO == null) {
            // 查询是否存在对应月份账单，不存在则新增
            billDO = new CreditBillDO();
            billDO.setCreditId(creditDO.getId());
            billDO.setBillBelongTime(billBelongTime);
            billDO.setBillDay(creditDO.getBillDay());
            billDO.setRepayPeriod(creditDO.getRepayPeriod());
            Date expireTime = CreditUtil.getExpireTime(DateUtil.date(billBelongTime), creditDO.getBillDay(), creditDO.getRepayPeriod());
            billDO.setExpireTime(expireTime.getTime());
        } else {
            billDO.setUpdateTime(System.currentTimeMillis());
        }
        billDO.setBillQuota(billDO.getBillQuota() + payVO.getPayMoney());
        billRepository.saveAndFlush(billDO);

        // 新增交易记录
        CreditTradeRecordDO recordDO = new CreditTradeRecordDO();
        recordDO.setCreditId(billDO.getCreditId());
        recordDO.setBillId(billDO.getId());
        String tradeCode = SerialNumberUtils.getNumber(redisStringUtils, Constants.CREDIT_TRACE_CODE, com.ssy.lingxi.common.constant.Constants.REDIS_ORDER_INDEX, Constants.CREDIT_TRACE_CODE_DATE, Constants.CREDIT_TRACE_CODE_NUM_LEN);
        recordDO.setTradeCode(tradeCode);
        recordDO.setTradeTime(System.currentTimeMillis());
        recordDO.setTradeMoney(payVO.getPayMoney());
        recordDO.setOperation(CreditTradeOperationEnum.PAY.getCode());
        recordDO.setStatus(CreditTradeStatusEnum.CONFIRM_RECEIPT.getCode());
        recordDO.setOrderCode(payVO.getOrderCode());
        recordDO.setTradeType(CreditTradeConstant.TradeType.ONLINE);
        recordDO.setTradeChannel(CreditTradeConstant.TradeChannel.CREDIT);
        recordDO.setRemark(payVO.getRemark());
        recordDO.setIsTemp(CommonBooleanEnum.NO.getCode());
        tradeRecordRepository.saveAndFlush(recordDO);

        // 更新授信
        creditDO.setUseQuota(creditDO.getUseQuota() + payVO.getPayMoney());
        //如果当前还款状态为：账单已还清则在支付后修改还款状态为：账单待还，其他状态不做修改
        if (CreditRepayStatusEnum.PAY_OFF.getCode().equals(creditDO.getRePayStatus())) {
            creditDO.setRePayStatus(CreditRepayStatusEnum.WAIT_REPAY.getCode());
        }
        creditDO.setUpdateTime(System.currentTimeMillis());
        creditRepository.saveAndFlush(creditDO);

        CreditPayResponseVO result = new CreditPayResponseVO();
        result.setPayId(recordDO.getId());
        result.setPayCode(recordDO.getTradeCode());

        return Wrapper.success(result);
    }

    /**
     * 授信还款
     * @param user 登录用户
     * @param vo 接口参数
     * @param httpRequest Http请求
     * @return 还款结果
     */
    @Override
    @Transactional
    public Wrapper<CreditRepayResultVO> repay(UserLoginCacheDTO user, CreditRepayVO vo, HttpServletRequest httpRequest) {

        if (!CreditTradeConstant.TradeType.ONLINE.equals(vo.getTradeType())
                && !CreditTradeConstant.TradeType.OFFLINE.equals(vo.getTradeType())) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_PAY_TRADE_TYPE_ERROR);
        }
        if (CreditTradeConstant.TradeType.OFFLINE.equals(vo.getTradeType())) {
            if (vo.getPayProveList() == null || vo.getPayProveList().size() <= 0) {
                return Wrapper.fail(ResponseCode.PAY_CREDIT_OFFLINE_PAY_PROVE_EMPTY);
            }
            for (PayProveBO proveBO : vo.getPayProveList()) {
                if (!StringUtils.hasLength(proveBO.getName()) || !StringUtils.hasLength(proveBO.getProveUrl())) {
                    return Wrapper.fail(ResponseCode.PAY_CREDIT_OFFLINE_PAY_PROVE_PARAM_ERROR);
                }
            }
        } else {
            if (!CreditTradeConstant.TradeChannel.WECHAT.equals(vo.getTradeChannel())
                    && !CreditTradeConstant.TradeChannel.ALI.equals(vo.getTradeChannel())
                    && !CreditTradeConstant.TradeChannel.UNION.equals(vo.getTradeChannel())
                    && !CreditTradeConstant.TradeChannel.BALANCE.equals(vo.getTradeChannel())) {
                return Wrapper.fail(ResponseCode.PAY_CREDIT_PAY_TRADE_CHANNEL_ERROR);
            }
        }

        CreditBillDO billDO = billRepository.findById(vo.getBillId()).orElse(null);
        if (billDO == null) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_BILL_NOT_EXIST);
        }
        BigDecimal billQuota = new BigDecimal(Double.toString(billDO.getBillQuota()));
        BigDecimal repayQuota = new BigDecimal(Double.toString(billDO.getRepayQuota()));
        if (billQuota.subtract(repayQuota).doubleValue() < vo.getRepayQuota()) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_OVERSTEP_BILL_REPAY);
        }
        if (billDO.getWaitConfirmRepayQuota() > 0) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_BILL_LAST_REPAY_NOT_CONFIRM);
        }
        CreditDO creditDO = creditRepository.findById(billDO.getCreditId()).orElse(null);
        if (creditDO == null) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_NOT_EXIST);
        }

        // 线下交易才需要设置待确认还款金额
        if (CreditTradeConstant.TradeType.OFFLINE.equals(vo.getTradeType())) {
            billDO.setWaitConfirmRepayQuota(billDO.getWaitConfirmRepayQuota() + vo.getRepayQuota());
        }
        // 更新账单记录
        // 待确认还款=原待确认还款+还款额度
        billDO.setLastRepayDate(System.currentTimeMillis());
        billDO.setUpdateTime(System.currentTimeMillis());
        billRepository.saveAndFlush(billDO);

        // 新增交易记录
        CreditTradeRecordDO recordDO = new CreditTradeRecordDO();
        recordDO.setCreditId(billDO.getCreditId());
        recordDO.setBillId(billDO.getId());
        String tradeCode = SerialNumberUtils.getNumber(redisStringUtils, Constants.CREDIT_TRACE_CODE, com.ssy.lingxi.common.constant.Constants.REDIS_ORDER_INDEX, Constants.CREDIT_TRACE_CODE_DATE, Constants.CREDIT_TRACE_CODE_NUM_LEN);
        recordDO.setTradeCode(tradeCode);
        recordDO.setTradeTime(System.currentTimeMillis());
        recordDO.setTradeMoney(vo.getRepayQuota());
        recordDO.setOperation(CreditTradeOperationEnum.REPAY.getCode());
        recordDO.setStatus(CreditTradeStatusEnum.WAIT_CONFIRM.getCode());
        recordDO.setRemark("");
        recordDO.setOrderCode("");
        recordDO.setTradeType(vo.getTradeType());
        recordDO.setTradeChannel(vo.getTradeChannel());
        recordDO.setPayProveList(vo.getPayProveList());
        // 如果是线上还款，交易记录默认为临时
        if (CreditTradeConstant.TradeType.ONLINE.equals(vo.getTradeType())) {
            recordDO.setIsTemp(CommonBooleanEnum.YES.getCode());
        } else {
            recordDO.setIsTemp(CommonBooleanEnum.NO.getCode());
        }
        tradeRecordRepository.saveAndFlush(recordDO);

        CreditRepayResultVO result = new CreditRepayResultVO();
        result.setRecordId(recordDO.getId());
        result.setStatus(recordDO.getStatus());
        result.setStatusName(CreditTradeStatusEnum.getItemMessage(recordDO.getStatus()));

        if (CreditTradeConstant.TradeType.ONLINE.equals(vo.getTradeType())) {
            // 如果是线上微信还款，则返回支付二维码收款字符串
            if (CreditTradeConstant.TradeChannel.WECHAT.equals(vo.getTradeChannel())) {
                MobilePayRequest mobilePayRequest = new MobilePayRequest();
                mobilePayRequest.setMemberId(creditDO.getParentMemberId());
                mobilePayRequest.setMemberRoleId(creditDO.getParentMemberRoleId());
                mobilePayRequest.setOrderCode(recordDO.getTradeCode());
                mobilePayRequest.setPayMoney(recordDO.getTradeMoney());
                mobilePayRequest.setServiceType(ServiceTypeEnum.Pay_Credit.getCode());
                mobilePayRequest.setRemark("授信微信还款");
                Wrapper<String> wrapper = feignService.creditWeChatRepay(mobilePayRequest, PayTypeEnum.Member.getCode(), httpRequest);
                if(wrapper == null){
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Wrapper.fail(ResponseCode.FEIGN_SERVICE_ERROR);
                }else if(wrapper.getCode() != ResponseCode.SUCCESS.getCode()){
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Wrapper.fail(wrapper);
                }

                result.setPayQRCode(wrapper.getData());
            } else if (CreditTradeConstant.TradeChannel.BALANCE.equals(vo.getTradeChannel())) {
                BalancePayRequest payRequest = new BalancePayRequest();
                payRequest.setMemberId(creditDO.getMemberId());
                payRequest.setMemberRoleId(creditDO.getMemberRoleId());
                payRequest.setParentMemberId(creditDO.getParentMemberId());
                payRequest.setParentMemberRoleId(creditDO.getParentMemberRoleId());
                payRequest.setOrderCode(recordDO.getTradeCode());
                payRequest.setPayMoney(recordDO.getTradeMoney());
                payRequest.setPayPassword(vo.getPassWord());
                payRequest.setPayType(PayTypeEnum.Member.getCode());
                payRequest.setRemark("授信余额还款");
                Wrapper<String> wrapper = feignService.creditBalanceRepay(payRequest);
                if(wrapper == null){
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Wrapper.fail(ResponseCode.FEIGN_SERVICE_ERROR);
                }else if(wrapper.getCode() != ResponseCode.SUCCESS.getCode()){
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Wrapper.fail(wrapper);
                }
                recordDO.setStatus(CreditTradeStatusEnum.CONFIRM_RECEIPT.getCode());
                recordDO.setRemark("余额还款：" + wrapper.getData());
                recordDO.setIsTemp(CommonBooleanEnum.NO.getCode());
                tradeRecordRepository.saveAndFlush(recordDO);

                // 修改账单
                billDO.setRepayQuota(billDO.getRepayQuota() + recordDO.getTradeMoney());
                billDO.setLastRepayDate(System.currentTimeMillis());
                billDO.setLastRepayQuota(recordDO.getTradeMoney());
                // 账单已还清时，记录最后还清时间
                if (billDO.getBillQuota() <= billDO.getRepayQuota()) {
                    billDO.setPayOffDate(System.currentTimeMillis());
                }
                // 上线还款没有待确认还款金额
                billDO.setUpdateTime(System.currentTimeMillis());
                billRepository.saveAndFlush(billDO);

                // 更新授信还款状态
                updateCreditRepayStatus(creditDO, billDO, recordDO.getTradeMoney());

                result.setStatus(recordDO.getStatus());
                result.setStatusName(CreditTradeStatusEnum.getItemMessage(recordDO.getStatus()));
            } else {
                // 其他还款方式尚未对接
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Wrapper.fail(ResponseCode.PAY_CREDIT_PAY_TRADE_CHANNEL_ERROR);
            }
        }

        // 如果是线下还款,更改授信还款状态为待确认还款
        if (CreditTradeConstant.TradeType.OFFLINE.equals(vo.getTradeType())) {
            creditDO.setRePayStatus(CreditRepayStatusEnum.WAIT_CONFIRM.getCode());
            creditRepository.saveAndFlush(creditDO);
        }

        return Wrapper.success(result);
    }

    /**
     * 获取授信还款结果
     * @param user 登录用户
     * @param recordId 记录Id
     * @return 查询结果
     */
    @Override
    public Wrapper<CreditRepayResultVO> getCreditRepayResult(UserLoginCacheDTO user, Long recordId) {
        CreditTradeRecordDO recordDO = tradeRecordRepository.findById(recordId).orElse(null);
        if (recordDO == null) {
           return Wrapper.fail(ResponseCode.PAY_CREDIT_TRADE_RECORD_NOT_EXIST);
        }

        CreditRepayResultVO result = new CreditRepayResultVO();
        result.setRecordId(recordId);
        result.setStatus(recordDO.getStatus());
        result.setStatusName(CreditTradeStatusEnum.getItemMessage(recordDO.getStatus()));

        return Wrapper.success(result);
    }

    /**
     * 确认还款成功
     * @param tradeCode 交易单号
     * @param orderCode 订单号
     */
    @Override
    public void confirmRepaySucceed(String tradeCode, String orderCode) {
        CreditTradeRecordDO recordDO = tradeRecordRepository.findByTradeCode(tradeCode);
        if (recordDO == null) {
            logger.info("确认还款失败，没有找到指定的交易记录：{}", tradeCode);
            throw new BusinessException(ResponseCode.PAY_CREDIT_TRADE_RECORD_NOT_EXIST);
        }
        if (!CreditTradeStatusEnum.WAIT_CONFIRM.getCode().equals(recordDO.getStatus())) {
            logger.info("确认还款失败：{}，现有状态为：{}", tradeCode, recordDO.getStatus());
            throw new BusinessException(ResponseCode.PAY_CREDIT_TRADE_RECORD_STATUS_PARAM_ERROR);
        }
        CreditBillDO billDO = billRepository.findById(recordDO.getBillId()).orElse(null);
        if (billDO == null) {
            logger.info("确认还款失败，没有找到指定的账单：{}", recordDO.getBillId());
            throw new BusinessException(ResponseCode.PAY_CREDIT_BILL_NOT_EXIST);
        }
        CreditDO creditDO = creditRepository.findById(recordDO.getCreditId()).orElse(null);
        if (creditDO == null) {
            logger.info("确认还款失败，没有找到指定的授信：{}", recordDO.getCreditId());
            throw new BusinessException(ResponseCode.PAY_CREDIT_NOT_EXIST);
        }

        // 修改交易记录
        recordDO.setIsTemp(CommonBooleanEnum.NO.getCode());
        recordDO.setOrderCode(orderCode);
        recordDO.setStatus(CreditTradeStatusEnum.CONFIRM_RECEIPT.getCode());
        tradeRecordRepository.saveAndFlush(recordDO);

        // 修改账单
        billDO.setRepayQuota(billDO.getRepayQuota() + recordDO.getTradeMoney());
        billDO.setLastRepayDate(System.currentTimeMillis());
        billDO.setLastRepayQuota(recordDO.getTradeMoney());
        // 账单已还清时，记录最后还清时间
        if (billDO.getBillQuota() <= billDO.getRepayQuota()) {
            billDO.setPayOffDate(System.currentTimeMillis());
        }
        // 上线还款没有待确认还款金额
        billDO.setUpdateTime(System.currentTimeMillis());
        billRepository.saveAndFlush(billDO);

        // 更新授信还款状态
        updateCreditRepayStatus(creditDO, billDO, recordDO.getTradeMoney());

    }

    /**
     * 确认还款
     * @param user 登录用户
     * @param vo 接口参数
     * @return 还款结果
     */
    @Override
    @Transactional
    public Wrapper<Void> confirmRepay(UserLoginCacheDTO user, CreditConfirmRepayVO vo) {
        if (!vo.getStatus().equals(CreditTradeStatusEnum.CONFIRM_NOT_RECEIPT.getCode())
                && !vo.getStatus().equals(CreditTradeStatusEnum.CONFIRM_RECEIPT.getCode())) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_TRADE_RECORD_STATUS_PARAM_ERROR);
        }

        CreditTradeRecordDO recordDO = tradeRecordRepository.findById(vo.getRecordId()).orElse(null);
        if (recordDO == null) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_TRADE_RECORD_NOT_EXIST);
        }

        if (!CreditTradeStatusEnum.WAIT_CONFIRM.getCode().equals(recordDO.getStatus())) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_TRADE_RECORD_NOT_WAIT_CONFIRM);
        }

        CreditBillDO billDO = billRepository.findById(recordDO.getBillId()).orElse(null);
        if (billDO == null) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_BILL_NOT_EXIST);
        }

        CreditDO creditDO = creditRepository.findById(recordDO.getCreditId()).orElse(null);
        if (creditDO == null) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_NOT_EXIST);
        }

        // 修改交易记录
        recordDO.setStatus(vo.getStatus());
        tradeRecordRepository.saveAndFlush(recordDO);

        // 修改账单
        if (CreditTradeStatusEnum.CONFIRM_RECEIPT.getCode().equals(vo.getStatus())) {
            billDO.setRepayQuota(billDO.getRepayQuota() + recordDO.getTradeMoney());

            billDO.setLastRepayDate(System.currentTimeMillis());
            billDO.setLastRepayQuota(recordDO.getTradeMoney());
            // 账单已还清时，记录最后还清时间
            if (billDO.getBillQuota() <= billDO.getRepayQuota()) {
                billDO.setPayOffDate(System.currentTimeMillis());
            }

            // 更新授信还款状态
            updateCreditRepayStatus(creditDO, billDO, recordDO.getTradeMoney());
        }

        // 更新账单待还款金额
        billDO.setWaitConfirmRepayQuota(billDO.getWaitConfirmRepayQuota() - recordDO.getTradeMoney());
        billDO.setUpdateTime(System.currentTimeMillis());
        billRepository.saveAndFlush(billDO);

        // 已用额度大于0，授信还款状态修改为：账单待还
        if (creditDO.getUseQuota() > 0) {
            creditDO.setRePayStatus(CreditRepayStatusEnum.WAIT_REPAY.getCode());
            creditRepository.saveAndFlush(creditDO);
        }

        return Wrapper.success();
    }

    /**
     * 更新授信还款状态（内部接口不验证参数）
     * @author 伍将
     * @date 2021/1/11
     * @param creditDO: 授信
     * @param billDO: 账单
     * @param tradeMoney: 交易金额
     **/
    @Transactional
    public void updateCreditRepayStatus(CreditDO creditDO, CreditBillDO billDO, Double tradeMoney) {

        // 修改授信
        creditDO.setUseQuota(creditDO.getUseQuota() - tradeMoney);
        creditDO.setLastRepayTime(System.currentTimeMillis());
        creditDO.setUpdateTime(System.currentTimeMillis());
        // 已用额度小于等于0，授信还款状态修改为：账单已还清，反之修改为：账单待还
        if (creditDO.getUseQuota() <= 0) {
            creditDO.setRePayStatus(CreditRepayStatusEnum.PAY_OFF.getCode());
        } else {
            creditDO.setRePayStatus(CreditRepayStatusEnum.WAIT_REPAY.getCode());
        }

        // 账单已还清时，查询是否还有逾期记录
        if (billDO.getBillQuota() <= billDO.getRepayQuota()) {
            // 查询除当前账单其他未还完逾期账单
            CreditBillDO billDO1 = getOldestOverdue(billDO.getCreditId(), billDO.getId());
            // 有逾期，则更改授信到期日期，还款状态为：逾期
            if (billDO1 != null) {
                creditDO.setExpireTime(billDO1.getExpireTime());
                creditDO.setRePayStatus(CreditRepayStatusEnum.OVERDUE.getCode());
            }
        } else {
            // 如果当前账单为逾期账单（到期时间早已系统当前时间），修改授信还款状态为：逾期
            if (billDO.getExpireTime() < System.currentTimeMillis()) {
                creditDO.setExpireTime(billDO.getExpireTime());
                creditDO.setRePayStatus(CreditRepayStatusEnum.OVERDUE.getCode());
            }
        }

        creditDO.setUpdateTime(System.currentTimeMillis());
        creditRepository.saveAndFlush(creditDO);
    }

    /**
     * 获取最旧的逾期账单
     * @author 伍将
     * @date 2020/8/28
     * @param creditId:
     * @param billId:
     * @return com.ssy.lingxi.pay.entity.CreditBillDO
     **/
    private CreditBillDO getOldestOverdue(Long creditId, Long billId) {
        // 组装查询条件
        Specification<CreditBillDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            // 指定授信id
            list.add(criteriaBuilder.equal(root.get("creditId").as(Long.class), creditId));
            // 已到期
            list.add(criteriaBuilder.lessThan(root.get("expireTime").as(Long.class), System.currentTimeMillis()));
            // 还款额度小于账单额度
            list.add(criteriaBuilder.lessThan(root.get("repayQuota").as(Long.class), root.get("billQuota").as(Long.class)));
            // 排除当前账单
            list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), billId));

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        return billRepository.findAll(spec, Sort.by(Sort.Order.asc("expireTime"))).stream().findFirst().orElse(null);
    }

    /**
     * 退款
     * @param refundVO 接口参数
     * @return 退款交易号
     */
    @Override
    @Transactional
    public Wrapper<String> refund(CreditRefundVO refundVO) {
        CreditTradeRecordDO recordDO = tradeRecordRepository.findByTradeCode(refundVO.getPayCode());
        if (recordDO == null) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_PAY_RECORD_NOT_EXIST);
        }

        if (recordDO.getTradeMoney() < refundVO.getRefundAmount() || refundVO.getRefundAmount() < 0) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_REFUND_AMOUNT_ERROR);
        }

        if (!recordDO.getTradeCode().equals(refundVO.getPayCode())) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_PAY_RECORD_TRADE_CODE_ERROR);
        }

        // 查询已退款金额
        Double tradeMoney = tradeRecordRepository.sumTradeMoney(recordDO.getBillId(), CreditTradeOperationEnum.REFUND.getCode(), recordDO.getId().toString());
        tradeMoney = (null != tradeMoney ? tradeMoney : 0);
        if (recordDO.getTradeMoney() < (refundVO.getRefundAmount() + tradeMoney)) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_REFUND_AMOUNT_ERROR);
        }
        CreditBillDO billDO = billRepository.findById(recordDO.getBillId()).orElse(null);
        if (billDO == null) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_BILL_NOT_EXIST);
        }

        CreditDO creditDO = creditRepository.findById(billDO.getCreditId()).orElse(null);
        if (creditDO == null) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_NOT_EXIST);
        }

        if (!creditDO.getMemberId().equals(refundVO.getMemberId()) || !creditDO.getMemberRoleId().equals(refundVO.getMemberRoleId())
                || !creditDO.getParentMemberId().equals(refundVO.getParentMemberId()) || !creditDO.getParentMemberRoleId().equals(refundVO.getParentMemberRoleId())) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_PAY_RECORD_NOT_EXIST);
        }

        // 修改账单
        billDO.setRefundQuota(billDO.getRefundQuota() + refundVO.getRefundAmount());
        billDO.setRepayQuota(billDO.getRepayQuota() + refundVO.getRefundAmount());
        billDO.setLastRepayDate(System.currentTimeMillis());
        billDO.setLastRepayQuota(refundVO.getRefundAmount());
        // 账单已还清时，记录最后还清时间
        if (billDO.getBillQuota() <= billDO.getRepayQuota()) {
            billDO.setPayOffDate(System.currentTimeMillis());
        }
        billDO.setUpdateTime(System.currentTimeMillis());
        billRepository.saveAndFlush(billDO);

        // 更新授信还款状态
        updateCreditRepayStatus(creditDO, billDO, refundVO.getRefundAmount());

        // 新增退款交易记录，原支付信息复制到退款记录中
        CreditTradeRecordDO recordAddDO = new CreditTradeRecordDO();
        recordAddDO.setCreditId(billDO.getCreditId());
        recordAddDO.setBillId(billDO.getId());
        String tradeCode = SerialNumberUtils.getNumber(redisStringUtils, Constants.CREDIT_TRACE_CODE, com.ssy.lingxi.common.constant.Constants.REDIS_ORDER_INDEX, Constants.CREDIT_TRACE_CODE_DATE, Constants.CREDIT_TRACE_CODE_NUM_LEN);
        recordAddDO.setTradeCode(tradeCode);
        recordAddDO.setTradeTime(System.currentTimeMillis());
        recordAddDO.setTradeMoney(refundVO.getRefundAmount());
        recordAddDO.setOperation(CreditTradeOperationEnum.REFUND.getCode());    // 设置退款
        recordAddDO.setStatus(CreditTradeStatusEnum.CONFIRM_RECEIPT.getCode()); // 退款直接到账
        recordAddDO.setRemark(refundVO.getRemark());
        recordAddDO.setOrderCode(recordDO.getId().toString());  // 设置原始支付记录Id为订单id
        recordAddDO.setTradeType(recordDO.getTradeType());
        recordAddDO.setTradeChannel(recordDO.getTradeChannel());
        recordAddDO.setIsTemp(CommonBooleanEnum.NO.getCode());
        recordAddDO.setPayProveList(null);
        tradeRecordRepository.saveAndFlush(recordAddDO);

        return Wrapper.success(recordAddDO.getTradeCode());
    }

    /**
     * 采购商分页查询会员列表页面搜索条件内容
     * @param user 登录用户
     * @return 查询结果
     */
    @Override
    public Wrapper<CreditPageItemsVO> pageItemsByConsumer(UserLoginCacheDTO user) {
        CreditPageItemsVO result = new CreditPageItemsVO();
        // 组装授信状态
        result.setStatusList(convertCreditStatus());
        // 组装还款状态
        result.setRepayStatusList(convertCreditRepayStatus());
        // 组装外部状态
        result.setOuterStatusList(convertCreditOuterStatus(false));
        // 组装内部状态
        result.setInnerStatusList(convertCreditInnerStatus(false));

        return Wrapper.success(result);
    }

    /**
     * 供应商商分页查询会员列表页面搜索条件内容
     * @param user 登录用户
     * @return 查询结果
     */
    @Override
    public Wrapper<CreditPageItemsVO> pageItemsBySupplier(UserLoginCacheDTO user) {

        CreditPageItemsVO result = new CreditPageItemsVO();

        // 组装授信状态
        result.setStatusList(convertCreditStatus());
        // 组装还款状态
        result.setRepayStatusList(convertCreditRepayStatus());
        // 组装外部状态
        result.setOuterStatusList(convertCreditOuterStatus(true));
        // 组装内部状态
        result.setInnerStatusList(convertCreditInnerStatus(true));
        // 组装申请类型
        result.setApplyTypeList(convertCreditApplyType());

        return Wrapper.success(result);
    }

    /**
     * 获取授信
     * @param user 登录用户
     * @param request 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<CreditVO> getCredit(UserLoginCacheDTO user, CreditVORequest request) {

        CreditRequestVO requestVO = new CreditRequestVO();
        requestVO.setMemberId(user.getMemberId());
        requestVO.setRoleId(user.getMemberRoleId());
        requestVO.setParentMemberId(request.getParentMemberId());
        requestVO.setParentMemberRoleId(request.getParentMemberRoleId());

        return getCreditDetail(requestVO);
    }

    /**
     * 获取会员授信
     * @param user 登录用户
     * @param request 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<CreditVO> getMemberCredit(UserLoginCacheDTO user, CreditRequestVO request) {
        return getCreditDetail(request);
    }

    /**
     * 获取授信信息
     * @author 伍将
     * @date 2020/12/28
     * @param request 上、下级会员Id和角色Id
     * @return 查询结果
     **/
    @Override
    public Wrapper<CreditVO> getCreditDetail(CreditRequestVO request) {
        // 验证授信是否存在
        CreditDO creditDO = this.creditRepository.findFirstByMemberIdAndMemberRoleIdAndParentMemberIdAndParentMemberRoleId(
                request.getMemberId(), request.getRoleId(), request.getParentMemberId(), request.getParentMemberRoleId());
        if (creditDO == null) {
            return Wrapper.fail(ResponseCode.PAY_CREDIT_NOT_EXIST);
        }

        CreditVO result = new CreditVO();

        // 赋值授信信息
        result.setQuota(creditDO.getQuota());
        result.setUseQuota(creditDO.getUseQuota());
        result.setCanUseQuota(creditDO.getQuota() - creditDO.getUseQuota());
        result.setIsUsable(CommonBooleanEnum.NO.getCode());
        if (creditDO.getIsUsable().equals(CommonBooleanEnum.YES.getCode())) {
            Boolean isOpen = feignService.isCreditPayment(creditDO.getParentMemberId(), creditDO.getParentMemberRoleId());
            if (isOpen) {
                result.setIsUsable(CommonBooleanEnum.YES.getCode());
            }
        }

        return Wrapper.success(result);
    }

    /**
     * 组装授信状态
     * @author 伍将
     * @date 2020/10/16
     * @return java.util.List<com.ssy.lingxi.pay.model.vo.response.CreditPageItemVO>
     **/
    private List<CreditPageItemVO> convertCreditStatus() {
        return Arrays.stream(CreditStatusEnum.values()).map(r -> {
            CreditPageItemVO status = new CreditPageItemVO();
            status.setStatus(r.getCode());
            status.setName(r.getMessage());
            return status;
        }).collect(Collectors.toList());
    }

    /**
     * 组装授信还款状态
     * @author 伍将
     * @date 2020/10/16
     * @return java.util.List<com.ssy.lingxi.pay.model.vo.response.CreditPageItemVO>
     **/
    private List<CreditPageItemVO> convertCreditRepayStatus() {
        return Arrays.stream(CreditRepayStatusEnum.values()).map(r -> {
            CreditPageItemVO status = new CreditPageItemVO();
            status.setStatus(r.getCode());
            status.setName(r.getMessage());
            return status;
        }).collect(Collectors.toList());
    }

    /**
     * 组装授信申请外部状态
     * @author 伍将
     * @date 2020/10/16
     * @param isSupplier:
     * @return java.util.List<com.ssy.lingxi.pay.model.vo.response.CreditPageItemVO>
     **/
    private List<CreditPageItemVO> convertCreditOuterStatus(Boolean isSupplier) {

        return Arrays.stream(CreditApplyOuterStatusEnum.values()).filter(r -> {
            if (isSupplier) {
                return !r.getCode().equals(CreditApplyOuterStatusEnum.WAIT_SUBMIT.getCode());
            } else {
                return true;
            }
        }).map(r -> {
            CreditPageItemVO status = new CreditPageItemVO();
            status.setStatus(r.getCode());
            status.setName(r.getMessage());
            return status;
        }).collect(Collectors.toList());
    }

    /**
     * 组装授信申请内部状态
     * @author 伍将
     * @date 2020/10/16
     * @param isSupplier:
     * @return java.util.List<com.ssy.lingxi.pay.model.vo.response.CreditPageItemVO>
     **/
    private List<CreditPageItemVO> convertCreditInnerStatus(Boolean isSupplier) {

        if (isSupplier) {
            return Arrays.stream(CreditApplySuperiorInnerStatusEnum.values()).map(r -> {
                CreditPageItemVO status = new CreditPageItemVO();
                status.setStatus(r.getCode());
                status.setName(r.getMessage());
                return status;
            }).collect(Collectors.toList());
        } else {
            return Arrays.stream(CreditApplyLowerInnerStatusEnum.values()).map(r -> {
                CreditPageItemVO status = new CreditPageItemVO();
                status.setStatus(r.getCode());
                status.setName(r.getMessage());
                return status;
            }).collect(Collectors.toList());
        }
    }

    /**
     * 组装授信申请类型
     * @author 伍将
     * @date 2020/10/16
     * @return java.util.List<com.ssy.lingxi.pay.model.vo.response.CreditPageItemVO>
     **/
    private List<CreditPageItemVO> convertCreditApplyType() {
        return Arrays.stream(CreditApplyTypeEnum.values()).map(r -> {
            CreditPageItemVO status = new CreditPageItemVO();
            status.setStatus(r.getCode());
            status.setName(r.getMessage());
            return status;
        }).collect(Collectors.toList());
    }

    /**
     * 冻结授信
     * @param frozenCreditVO 接口参数
     * @return 冻结结果
     */
    @Override
    public Wrapper<Void> frozenCredit(FrozenCreditVO frozenCreditVO) {
        // step 1: 验证修改的状态符合要求
        if (!CommonBooleanEnum.YES.getCode().equals(frozenCreditVO.getStatus()) && !CommonBooleanEnum.NO.getCode().equals(frozenCreditVO.getStatus())) {
            throw new BusinessException(ResponseCode.PAY_CREDIT_STATUS_PARAM_ERROR);
        }

        // step 2: 验证授信是否存在
        CreditDO creditDO = this.creditRepository.findFirstByMemberIdAndMemberRoleIdAndParentMemberIdAndParentMemberRoleId(frozenCreditVO.getMemberId(), frozenCreditVO.getRoleId(), frozenCreditVO.getParentMemberId(), frozenCreditVO.getParentMemberRoleId());
        if (creditDO != null) {
            if (CommonBooleanEnum.YES.getCode().equals(frozenCreditVO.getStatus())) {
                creditDO.setIsUsable(CommonBooleanEnum.NO.getCode());
                creditDO.setStatus(CreditStatusEnum.FROZEN.getCode());
            } else {
                creditDO.setIsUsable(CommonBooleanEnum.YES.getCode());
                creditDO.setStatus(CreditStatusEnum.THAW.getCode());
            }
            creditDO.setUpdateTime(System.currentTimeMillis());

            this.creditRepository.saveAndFlush(creditDO);
        }

        return Wrapper.success();
    }

    /**
     * 获取可用余额
     * @param user 登录用户
     * @return 可用余额
     */
    @Override
    public Wrapper<Double> getCanUseQuota(UserLoginCacheDTO user) {
        return Wrapper.success(creditRepository.sumCanUseQuota(user.getMemberId(), user.getMemberRoleId()));
    }

    /**
     * 检查是否申请授信
     * @param user 登录用户
     * @return 检查结果
     */
    @Override
    public Wrapper<Boolean> existApplyCredit(UserLoginCacheDTO user) {
        Long count = creditRepository.existApplyCredit(user.getMemberId(), user.getMemberRoleId());
        return Wrapper.success(count > 0);
    }
}
